#页面基类：被每个页面类继承
#封装了每个UI都需要的一些通用操作！

from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.select import Select
import time,os,sys

class PageBase(object):

    def make_xpath_with_unit_feature(self, loc):
        args = loc.split(",")
        feature = ""  # 返回值

        if len(args) == 2:
            feature = "contains(@" + args[0] + ",'" + args[1] + "')" + "and "
        elif len(args) == 3:
            if args[2] == "1":
                feature = "@" + args[0] + "='" + args[1] + "'" + "and "
            elif args[2] == "0":
                feature = "contains(@" + args[0] + ",'" + args[1] + "')" + "and "
        return feature

    '''
    函数功能：给简化的xpath，函数返回标准的xpath字符串。
    即:
    如果loc = "text,设置"或"text,设置,0"，函数返回"//*[contains(@text,'设置')]"，情况1。
    如果loc = "text,设置,1"，函数返回"//*[@text='设置']"，情况2。
    如果loc = ["text,设置"] ，函数返回"//*[contains(@text,'设置')]"，情况1。
    如果loc = ["text,设置", "index,20,1", "index1,50"]，函数返回"//*[contains(@text,'设置')and@index='20'andcontains(@index1,'50')]"，情况3。
    如果loc = "//*[contains(@text,'设')]" ，即故意传个正常的xpath字符串，函数返回"//*[contains(@text,'设')]"，情况4。
    '''

    def make_xpath_with_feature(self, loc):
        feature_start = "//*["
        feature_end = "]"
        feature = ""

        # 如果传的是字符串，即情况1和情况2
        if isinstance(loc, str):
            # 如果是正常的xpath，即情况4
            if loc.startswith("//"):
                return loc
            feature = self.make_xpath_with_unit_feature(loc)
        else:  # 如果传的是列表，即情况3
            for i in loc:
                feature += self.make_xpath_with_unit_feature(i)

        feature = feature.rstrip("and ")  # 删除最右侧的"and "
        ret_loc = feature_start + feature + feature_end
        return ret_loc

    def __init__(self,driver,base_url):
        self.driver=driver
        self.base_url=base_url

    # 函数功能：根据元素特征loc返回该元素
    def find_element(self, loc):
        by=loc[0]
        value=loc[1] #简化xpath/标准xpath
        if by==By.XPATH:
            value=self.make_xpath_with_feature(value)
        return self.driver.find_element(by, value)

    #函数功能：根据元素loc返回一组元素
    def find_elements(self,loc):
        by = loc[0]
        value = loc[1]  # 简化xpath/标准xpath
        if by == By.XPATH:
            value = self.make_xpath_with_feature(value)
        return self.driver.find_elements(by, value)



    #函数功能：打开某url
    #形参url：端口后面的网址。类似"/user/login"
    def open(self,url):
        self.driver.get(self.base_url+url)



    #函数功能：点击某元素loc
    def click(self,loc):
        self.find_element(loc).click()

    #函数功能：对元素loc进行输入数据data
    #适合那些控件：文本框、密码框、多行文本框
    def input(self,loc,data):
        self.find_element(loc).send_keys(data)

    #函数功能：获取用户输入的数据！
    # 适合那些控件：文本框、密码框、多行文本框
    def get_TextBox(self,loc):
        return self.find_element(loc).get_attribute("value")


    #函数功能：清空元素loc中的数据
    # 适合那些控件：文本框、密码框、多行文本框
    def clear(self,loc):
        self.find_element(loc).clear()

    #函数功能：获取某元素loc的文本内容
    def getEleText(self,loc):
        return self.find_element(loc).text

    #函数功能：获取某元素loc和某属性attr的值
    def getEleAttr(self,loc,attr):
        return self.find_element(loc).get_attribute(attr)


    # 功能：选中单选按钮的某选项
    def click_radio(self, attr_name, attr_value):
        self.driver.find_element_by_css_selector(f"input[type='radio'][name='{attr_name}'][value='{attr_value}']").click()

    # 功能：对于单选按钮，获取用户选中的是那个选项
    # 返回值：选中的那个选项的value属性的值
    def getXuanzonRadio(self, attr_name):
        all_xuanxian = self.driver.find_elements_by_css_selector(f"input[type='radio'][name='{attr_name}']")
        user_value = ""
        for x in all_xuanxian:
            xuanzonStatus = x.is_selected()
            if xuanzonStatus:
                user_value = x.get_attribute("value")
                break

        return user_value

    # 功能：对于复选框，选中某些选项！
    def click_checkbox(self, attr_name, user_values):
        all_xuanxian = self.driver.find_elements_by_css_selector(f"input[type='checkbox'][name='{attr_name}']")
        for x in all_xuanxian:
            attr_value = x.get_attribute("value")
            xuanZonStatus = x.is_selected()
            if attr_value in user_values:  # 确保该选项选中
                if xuanZonStatus:  # 如果该选项的当前状态是已选中
                    pass
                else:  # 如果该选项的当前状态是不选中
                    x.click()
            else:  # 确保该选项不被选中
                if xuanZonStatus:  # 如果该选项的当前状态是已选中
                    x.click()
                else:  # 如果该选项的当前状态是不选中
                    pass

    # 函数：对于复选框，获取用户选中了哪些选项！
    # 返回值：这些选中的选项的value的拼接！
    def getXuanzonCheckBox(self, attr_name):
        user_values = ""
        all_xuanxian = self.driver.find_elements_by_css_selector(f"input[type='checkbox'][name='{attr_name}']")
        for x in all_xuanxian:
            xuanZonStatus = x.is_selected()
            if xuanZonStatus:
                attr_value = x.get_attribute("value")
                user_values += attr_value + ","
        user_values = user_values[:-1]
        return user_values

    # 功能：对下拉列表，选中某选项！
    def click_select(self, attr_select_name, user_option_text):
        ele_select = self.driver.find_element_by_css_selector(f"select[name='{attr_select_name}']")
        select = Select(ele_select)
        select.select_by_visible_text(user_option_text)

    # 功能：对下拉列表，获取用户选中的哪个选项
    # 返回值：用户选中的那个选项的文本内容
    def getXuanZonSelect(self, attr_select_name):
        all_xuanxian = self.driver.find_elements_by_css_selector(f"select[name='{attr_select_name}'] > option")
        user_opton = ""
        for x in all_xuanxian:
            xuanZonStatus = x.is_selected()
            if xuanZonStatus:
                user_opton = x.text
                break
        return user_opton

    # 功能：用Selenium方式上传单个文件/单个目录！
    # 文件路径："C:/A/1.png"
    def uploadSingleFile_by_selenium(self, loc, filePath):
        self.find_element(loc).send_keys(filePath)

    # 功能：用Selenium方式上传多个文件/多个目录！
    # filesPath = "C:/A/1.png,C:/A/2.png"
    def uploadMulFiles_by_selenium(self, loc, filesPaths):
        filesPath = filesPaths.replace(",", "\n")
        self.find_element(loc).send_keys(filesPath)

    # 功能：用autoIT方式来上传单个文件/单个目录
    # filePath = "C:/A/1.png"
    def uploadSingleFile_by_autoIT(self, loc, filePath, exePath):
        # 步骤1：由Selenium完成：让window的“打开”窗口出现
        ele =self.find_element(loc)
        ActionChains(self.driver).click(ele).perform()
        # 步骤2和步骤2：由autoIT教程编译好的exe程序来完成，python调用exe程序即可
        time.sleep(2)
        filePath = filePath.replace("/", "\\")
        os.system(f"{exePath} {filePath}")

    # 功能：用autiIT方式来上传多个文件/多个目录
    # filesPath = "C:/A/1.png,C:/A/2.png"
    def uploadMulFile_by_autoIT(self, loc, filesPath, exePath):
        ele = self.find_element(loc)
        ActionChains(self.driver).click(ele).perform()

        time.sleep(2)
        ret = ''
        for x in filesPath.split(","):
            # x=C:\A\1.png
            x = x.replace("/", "\\")
            ret += '"' + x + '" '
        os.system(f'{exePath} {ret}')


    #功能：根据窗口标题(可以给部分值)来切换窗口
    def switchWindowsByTitle(self,target_title):
        for win in self.driver.window_handles:
            # 先切进到某窗口
            self.driver.switch_to.window(win)
            current_title = self.driver.title
            if target_title in current_title:
                break

    #功能：把当前UI截图保存到指定screen目录中！
    def savePng(self,serviceName,key):
        fileName=f'{serviceName}_{key}_{time.strftime("%Y%m%d%H%M%S")}.png'
        self.driver.get_screenshot_as_file(f"./screen/{fileName}")
        return fileName

